package com.netsdk.lht2.push;

import com.netsdk.demo.util.sql.Trajectory;
import com.netsdk.lht2.util.LocalDateTimeUtil;
import com.netsdk.lht2.util.RandomUtil;
import com.netsdk.lht2.util.TrajectoryUtil;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

public abstract class AbstractRoadVehicleData {
    protected Map<String, List<Trajectory[]>> data = new HashMap<>();
    protected Map<Direction, List<String>> directionMapping = new HashMap<>();
    protected Set<String> channelSet = new HashSet<>();
    protected String utc ;
    private final static   int MIN_NUM = 26;

    private final static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public AbstractRoadVehicleData(String utc) {
        this.utc = utc;
    }

    public abstract String getName();

    public void addData(String channel,String nlane,List<Trajectory[]> arr){
        String index = channel + "-" + nlane;
        List<Trajectory[]> trajectories = data.get(index);
        if(trajectories == null){
            data.put(index,arr);
        }else {
            index += "-";
            data.put(index,arr);
        }
    }

    public boolean support(String channel){
        return channelSet.contains(channel);
    }

    public List<Trajectory[]> getPushData(){
        // 预处理
        proprocess();
        TimeCacheUtil.TimeRecored timeRecored = TimeCacheUtil.get2(utc);
        LocalDateTime startTime = timeRecored.getStartTime();
        LocalDateTime   endTime ;
        boolean flag = false;
        while (true){
            endTime = deal(flag);
            System.out.println(String.format("%s,%s，最终使用时间：%s",getName(),utc,endTime));
            if(endTime.isAfter(startTime.plusSeconds(59))){
                System.out.println("超时："+endTime);
                randomRemoveVichleData(1);
            }else {
                Duration duration = Duration.between(endTime,startTime.plusMinutes(1));
                if(duration.toMillis()>12000){
                    if(flag){
                         // randomAddVichleData(1);
                        break;
                    }
                    flag = true;
                }else {
                    break;
                }
            }
        }
        // 更新日期
        timeRecored.setEndTime(endTime);
        timeRecored.status = 2;
//        StringBuilder sb = new StringBuilder();
        List<Trajectory[]> list = new ArrayList();
        for (Map.Entry<String, List<Trajectory[]>> entry : data.entrySet()) {
            List<Trajectory[]> value = entry.getValue();
            list.addAll(value);
//            String body = TrajectoryUtil.toPushStringList(value);
//            sb.append(body);
        }
        return list;
    }



    private LocalDateTime addTrajectoryTime(LocalDateTime startTime, Direction direction, boolean flag, int offset){
        List<String> indexList = directionMapping.get(direction);
        LocalDateTime endTime = startTime;
        for (String index : indexList) {
            List<Trajectory[]> trajectories = data.get(index);
            if(trajectories == null)continue;
            LocalDateTime oneEndTime = dealTime(trajectories, startTime, flag);
            if(oneEndTime.isAfter(endTime)){
                endTime = oneEndTime;
            }
        }
        if(endTime.isAfter(startTime)){
            endTime = endTime.plusSeconds(offset);
        }
        return endTime;
    }

    private LocalDateTime deal(boolean flag) {
        int offset = flag?4:3;

        TimeCacheUtil.TimeRecored timeRecored = TimeCacheUtil.get2(utc);
        LocalDateTime startTime = timeRecored.getStartTime();
        timeRecored.status = 1;
        // 东西直行
        LocalDateTime straightTime = addTrajectoryTime(startTime.plusSeconds(1), Direction.straight, flag,offset);
        // 东西右转
        LocalDateTime baseRightTime = startTime.plusSeconds(5);
        LocalDateTime rightTime = addTrajectoryTime(baseRightTime, Direction.right, flag,offset);
        // 东西左转
        LocalDateTime baseLeftTime = LocalDateTimeUtil.findMax(straightTime,rightTime).plusSeconds(1);
        LocalDateTime leftTime = addTrajectoryTime(baseLeftTime, Direction.left, flag,offset);
        // 南北直行
        LocalDateTime straightTime2 = addTrajectoryTime(leftTime, Direction.straight2, flag,offset);
        // 南北右转
        LocalDateTime baseRight2Time = leftTime.plusSeconds(4);
        LocalDateTime rightTime2 = addTrajectoryTime(baseRight2Time, Direction.right2, flag,5);
        // 南北左转
        LocalDateTime baseLeft2Time = LocalDateTimeUtil.findMax(rightTime2,straightTime2);
        LocalDateTime leftTime2 = addTrajectoryTime(baseLeft2Time, Direction.left2, flag,5);
        return leftTime2;
    }

    // 数据预处理
    private void proprocess() {
        int straightCount = countSumByDirection(Direction.straight);
        int rightCount = countSumByDirection(Direction.right);
        int leftCount = countSumByDirection(Direction.left);
        int straight2Count = countSumByDirection(Direction.straight2);
        int right2Count = countSumByDirection(Direction.right2);
        int left2Count = countSumByDirection(Direction.left2);
        int total = Math.max(straightCount,rightCount)+leftCount+Math.max(straight2Count,right2Count)+left2Count;
        if(total < MIN_NUM){
            // 补充车辆数据
            int addNum = MIN_NUM -total;
            // 直行
            fillVichleData((int)(addNum*0.3)+1, Direction.straight);
            // 左转
            fillVichleData( (int)(addNum*0.1)+1, Direction.left);
            // 右转
            fillVichleData( (int)(addNum*0.1)+1, Direction.right);

            fillVichleData( (int)(addNum*0.3)+1, Direction.straight2);
            fillVichleData( (int)(addNum*0.1)+1, Direction.left2);
            fillVichleData( (int)(addNum*0.1)+1, Direction.right2);
        }
    }

    public void fillVichleData(int num, Direction direction){
        for (int i = 0; i < num; i++) {
            List<String> mapping = directionMapping.get(direction);
            int length = mapping.size();
            String randomIndex = mapping.get(RandomUtil.getRandomValue(length));
            List<Trajectory[]> trajectories = data.computeIfAbsent(randomIndex, k -> new ArrayList<>());
            trajectories.addAll(TrajectoryUtil.create(TimeCacheUtil.formateUtc(utc),1,randomIndex.substring(0,3),randomIndex.substring(4)));
        }
    }

    public void randomRemoveVichleData(int num){
        for (int i = 0; i < num; i++) {
            Map.Entry<String, List<Trajectory[]>> entry = data.entrySet().stream().max(Comparator.comparingInt(o -> o.getValue().size())).get();
            entry.getValue().remove(0);
        }
    }

    public  void randomAddVichleData(int num){
//        for (int i = 0; i < num; i++) {
//            RandomUtil.getRandomValue()
//        }
    };

    private int countSumByDirection(Direction direction) {
        List<String> list = directionMapping.get(direction);
        int count = 0;
        for (String index : list) {
            List<Trajectory[]> trajectories = data.get(index);
            if(trajectories != null){
                count += trajectories.size();
            }
        }
        return count;
    }

    public int countTotal() {
        int straightCount = countSumByDirection(Direction.straight);
        System.out.println("straightCount:"+ straightCount);
        int rightCount = countSumByDirection(Direction.right);
        System.out.println("rightCount:"+ rightCount);
        int leftCount = countSumByDirection(Direction.left);
        System.out.println("leftCount:"+ leftCount);
        int straight2Count = countSumByDirection(Direction.straight2);
        System.out.println("straight2Count:"+ straight2Count);
        int right2Count = countSumByDirection(Direction.right2);
        System.out.println("right2Count:"+ right2Count);
        int left2Count = countSumByDirection(Direction.left2);
        System.out.println("left2Count:"+ left2Count);

//        for (Map.Entry<String, List<Trajectory[]>> entry : data.entrySet()) {
//            count += entry.getValue().size();
//            System.out.println(entry.getKey() + "  : "+ entry.getValue().size());
//        }
        return straightCount+rightCount+leftCount+straight2Count+right2Count+left2Count;
    }


    private LocalDateTime dealTime(List<Trajectory[]> data,LocalDateTime startTime,boolean flag){
        if(data==null){
            return startTime;
        }
        LocalDateTime endTime = startTime;
        for (Trajectory[] datum : data) {
            int delay = 0;
            for (Trajectory trajectory : datum) {
                trajectory.setTime(endTime.plusSeconds(delay).format(dateTimeFormatter));
                delay +=1;
            }
            if(flag){
                endTime = endTime.plusSeconds(RandomUtil.getRandomValue(2)+1);
            }else {
                endTime = endTime.plusSeconds(1);
            }
        }
        return endTime;
    }

    enum Direction {straight,right,left,straight2,right2,left2}

}
